﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

using SharedGenomics.Core;
using SharedGenomics.Annotations;

namespace SharedGenomics.Workbench.Annotations
{
    public class AnnotationPlanRunner : IAnnotationRequestStatusNotifiable
    {
        private readonly AnnotationRequestQueue _requestQueue;
        private AnnotationInfoSet _annotations;
        private IAnnotationPlan _plan;

        public AnnotationPlanRunner(AnnotationInfoSet annotations, AnnotationRequestQueue requestQueue)
        {
            annotations.ThrowIfNull("annotations");
            requestQueue.ThrowIfNull("requestQueue");

            this._annotations = annotations;
            this._requestQueue = requestQueue;
        }

        public virtual void Run(IAnnotationPlan plan)
        {
            plan.ThrowIfNull("plan");
            plan.RequestsFailed += this.Plan_RequestsFailed;

            //set plan and queue initial requests
            this._plan = plan;
            this.QueueRequests(plan.GetPendingRequests());
        }

        private void Plan_RequestsFailed(object sender, AnnotationPlanRequestsFailedEventArgs e)
        {
            e.FailedRequestKeys.ForEach(key => this._annotations.AnnotationFailed(key));
        }

        private void QueueRequests(IEnumerable<AnnotationKey> keys)
        {
            Debug.Assert(keys != null);
            Debug.Assert(this._annotations != null);

            foreach (var key in keys)
            {
                //queue request
                AnnotationRequestInfo requestInfo = new AnnotationRequestInfo { Key = key, RootValue = this.AnnotationTarget };
                this._requestQueue.QueueRequest(requestInfo);
            }
        }

        public object AnnotationTarget
        {
            get { return this._annotations.AnnotationTarget ; }
        }

        public void Notify(AnnotationRequestResult result)
        {
            result.ThrowIfNull("result");

            if (result.Status == AnnotationRequestStatus.Finished)
            {
                //add annotation key to plan along with those for any values
                this._plan.NotifyRequestFinished(result.Key);

                //add annotation to set
                this._annotations.AddAnnotation(result.Annotation);

                this.QueueRequests(this._plan.GetPendingRequests());
            }
            else if (result.Status == AnnotationRequestStatus.Failed)
            {
                this._plan.NotifyRequestFailed(result.Key);
            }
            else
            {
                //should not happen but it's not that serious...
                Debug.Fail("Notified of pending annotation request");
            }
        }
    }
}
